package main

import (
	"fmt"
	"time"
)

func main() {
	// 1、声明通道类型:
	// var ch1 chan int 只声明不分配，值是 nil,作为结构体字段占位
	// type TaskManager struct {
	// 	workCh chan int
	// }
	var ch1 chan int
	// 2、make(chan int) 会真正创建通道对象，值是非 nil 的引用
	ch2 := make(chan int)
	ch3 := make(chan interface{})
	fmt.Println(ch1, ch2, ch3)

	// 使用 make 创建一个通道后，就可以使用 <- 向通道发送数据
	// 把数据往通道中发送时，如果接收方一直都没有接收，那么发送操作将持续阻塞
	// ch <- "some info"

	// 使用通道接收数据
	// 	通道接收同样使用 <- 操作符，通道接收有如下特性：
	// 1、通道的收发操作在不同的两个 goroutine 间进行。
	// 由于通道的数据在没有接收方处理时，数据发送方会持续阻塞，因此通道的接收必定在另外一个 goroutine 中进行。
	// 2、接收将持续阻塞直到发送方发送数据。
	// 如果接收方接收时，通道中没有发送方发送数据，接收方也会发生阻塞，直到发送方发送数据为止。
	// 3、每次接收一个元素
	go func() {
		// 1、阻塞模式接收数据时，
		// 直到接收到数据并赋值给 data 变量将接收变量作为 <- 操作符的左值，格式如下：data := <-ch
		data := <-ch3
		fmt.Println("data is ", data)

		// 2、使用非阻塞方式从通道接收数据时，语句不会发生阻塞，格式如下：data, ok := <-ch
		// ok==false 表示通道已空且已关闭
		if data, ok := <-ch3; ok {
			fmt.Println("data is ", data)
		}

		// 3、接收任意数据，忽略接收的数据
		// 阻塞接收数据后，忽略从通道返回的数据，
		// 格式如下：<-ch

	}()
	ch3 <- "sss"
	channel_rang()
	time.Sleep(time.Second * 4)
}

// Go语言提倡使用通信的方法代替共享内存，
// 当一个资源需要在 goroutine 之间共享时，通道在 goroutine 之间架起了一个管道，并提供了确保同步交换数据的机制
// 每个 channel 都有一个特殊的类型，也就是 channels 可发送数据的类型

func channel_rang() {
	// 4、循环接收
	// 通道的数据接收可以借用 for range 语句进行多个元素的接收操作
	ch := make(chan int)

	go func() {
		for i := 3; i >= 0; i-- {
			ch <- i
			time.Sleep(time.Second)
		}

	}()
	// for-range 会自动检测到关闭并退出循环
	for data := range ch {

		fmt.Println(data)
		if data == 0 {
			break
		}
	}

}
